package org.wsiz.vro.security;

import static com.google.common.collect.Lists.newArrayList;

import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import org.wsiz.vro.domain.Account;
import org.wsiz.vro.repository.AccountRepository;

/**
 * An implementation of Spring Security's UserDetailsService.
 */
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    private static final Logger log = Logger.getLogger(UserDetailsServiceImpl.class);

    private AccountRepository accountRepository;

    @Autowired
    public UserDetailsServiceImpl(AccountRepository accountRepository) {
        this.accountRepository = accountRepository;
    }

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
        if (username == null || username.trim().isEmpty()) {
            throw new UsernameNotFoundException("Empty username");
        }

        if (log.isDebugEnabled()) {
            log.debug("Security verification for user '" + username + "'");
        }

        Account user = accountRepository.getByLogin(username);

        if (user == null) {
            if (log.isInfoEnabled()) {
                log.info("User " + username + " could not be found");
            }
            throw new UsernameNotFoundException("user " + username + " could not be found");
        }

        Collection<GrantedAuthority> grantedAuthorities = toGrantedAuthorities(user.getRoleNames());
        String password = user.getPassword();
        boolean enabled = user.getIsEnabled();
        boolean userNonExpired = true;
        boolean credentialsNonExpired = true;
        boolean userNonLocked = true;

        return new org.springframework.security.core.userdetails.User(username, password, enabled, userNonExpired,
                credentialsNonExpired, userNonLocked, grantedAuthorities);
    }

    public static Collection<GrantedAuthority> toGrantedAuthorities(List<String> roles) {
        List<GrantedAuthority> result = newArrayList();

        for (String role : roles) {
            result.add(new GrantedAuthorityImpl(role));
        }

        return result;
    }
}
